﻿

using Dapper;
using Lrd.Permissions.Core.Entity;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;

namespace Lrd.Permissions.Repository
{

    public class UnitOfWork : IUnitOfWork
    {
        private readonly List<DbContextBase> _dbContexts = new List<DbContextBase>();
        private readonly IServiceProvider _serviceProvider = null;
        private DbConnection _connection;
        private DbTransaction _transaction;
        private bool HasCommitted = false;
        public UnitOfWork(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        public DbContext GetDbContext<TEntity, TKey>() where TEntity : IEntity<TKey>
        {
            Type entityType = typeof(TEntity);
            return GetDbContext(entityType);
        }


        public DbContext GetDbContext(Type entityType)
        {
            IEntityManager manager = _serviceProvider.GetService(typeof(IEntityManager)) as IEntityManager;


            var dbContextType = manager.GetDbContextTypeForEntity(entityType);
            DbContextBase dbContext = _dbContexts.FirstOrDefault(m => m.GetType() == dbContextType);

            if (!(dbContext is null))
            {
                return dbContext;
            }

            dbContext = _serviceProvider.GetService(dbContextType) as DbContextBase;

            ///检测关系型数据库是否存在
            RelationalDatabaseCreator creator = dbContext.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator;
            if (creator==null && !creator.Exists())
            {
                throw new Exception($"数据上下文“{dbContext.GetType().FullName}”的数据库不存在，请通过 Migration 功能进行数据迁移创建数据库。");
            }
            _connection = dbContext.Database.GetDbConnection();
            _dbContexts.Add(dbContext);
            return dbContext;
        }


        public virtual void BeginOrUseTransaction()
        {
            if (_dbContexts.Count == 0)
            {
                return;
            }

            if (_transaction?.Connection == null)
            {
                if (_connection.State != ConnectionState.Open)
                {
                    _connection.Open();
                }

                _transaction = _connection.BeginTransaction();
            }

            foreach (DbContextBase context in _dbContexts)
            {
                if (context.Database.CurrentTransaction != null && context.Database.CurrentTransaction.GetDbTransaction() == _transaction)
                {
                    continue;
                }

                if (context.Database.GetService<IDbContextTransactionManager>() is IRelationalTransactionManager)
                {
                    context.Database.UseTransaction(_transaction);
                }
                else
                {
                    context.Database.BeginTransaction();
                }
            }
            HasCommitted = false;
        }



        /// <summary>
        /// 提交当前上下文的事务更改
        /// </summary>
        public virtual void Commit()
        {
            if (HasCommitted || _dbContexts.Count == 0 || _transaction == null)
            {
                return;
            }

            _transaction.Commit();
            foreach (DbContextBase context in _dbContexts)
            {
                if (context.Database.GetService<IDbContextTransactionManager>() is IRelationalTransactionManager)
                {
                    context.Database.CurrentTransaction.Dispose();
                    //关系型数据库共享事务
                    continue;
                }

                context.Database.CommitTransaction();
            }

            HasCommitted = true;
        }


        public IEnumerable<TResult> FromSql<TResult>(string sql, object param = null)
        {
            
            using (IDbConnection dbConnection = _connection)
            {

              return  dbConnection.Query<TResult>(sql,param);
            }
        }

        public async Task<IEnumerable<TResult>> FromSqlAsyc<TResult>(string sql, Dictionary<string,object> param=null)
        {

            DynamicParameters parameters = new DynamicParameters();

            if (param!=null)
            {
                parameters.AddDynamicParams(param);
            }
            //foreach (var item in param)
            //{
            //    parameters.Add(item.Key,item.Value);
            //}



            using (DbConnection dbConnection = _connection)
            {
              return  await dbConnection.QueryAsync<TResult>(sql, parameters);
            }

        }

    
    }
}
